package com.yair_srm.db.dao.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import com.yair_srm.db.dao.IGenericDAO;
import com.yair_srm.db.dao.util.PaginationSupport;

@SuppressWarnings("unchecked")
public class GenericDAO<T, ID extends Serializable>
        extends HibernateDaoSupport
        implements IGenericDAO<T, ID> {

    private Log logger = LogFactory.getLog(getClass());

    protected Class<T> entityClass;

    public GenericDAO() {
    }

    protected Class getEntityClass() {
        if (entityClass == null) {
            entityClass = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
            logger.debug("T class = " + entityClass.getName());
        }
        return entityClass;
    }

    public void saveOrUpdate(T t) throws DataAccessException {
        this.getHibernateTemplate().saveOrUpdate(t);
    }

    public T load(ID id) throws DataAccessException {
        return (T) getHibernateTemplate().load(getEntityClass(), id);
    }

    public T get(ID id) throws DataAccessException {
        return (T) getHibernateTemplate().get(getEntityClass(), id);
    }

    public boolean contains(T t) throws DataAccessException {
        return getHibernateTemplate().contains(t);
    }

    public void delete(T t, LockMode lockMode) throws DataAccessException {
        getHibernateTemplate().delete(t, lockMode);
    }

    public void delete(T t) throws DataAccessException {
        getHibernateTemplate().delete(t);
    }

    public void deleteAll(Collection<T> entities) throws DataAccessException {
        getHibernateTemplate().deleteAll(entities);
    }

    public List<T> find(String queryString, Object value)
            throws DataAccessException {
        return getHibernateTemplate().find(queryString, value);
    }

    public List<T> find(String queryString, Object[] values)
            throws DataAccessException {
        return getHibernateTemplate().find(queryString, values);
    }

    public List<T> findByCriteria(DetachedCriteria criteria)
            throws DataAccessException {
        return getHibernateTemplate().findByCriteria(criteria);
    }

    public List<T> findByExample(T exampleEntity) throws DataAccessException {
        return getHibernateTemplate().findByExample(exampleEntity);
    }

    public List<T> findByNamedParam(String queryString, String[] paramNames,
                                    Object[] values) throws DataAccessException {
        return getHibernateTemplate().findByNamedParam(queryString,
                paramNames, values);
    }

    public List<T> find(String queryString) throws DataAccessException {
        return getHibernateTemplate().find(queryString);
    }

    public void refresh(T t, LockMode lockMode) throws DataAccessException {
        getHibernateTemplate().refresh(t, lockMode);
    }

    public void refresh(T t) throws DataAccessException {
        getHibernateTemplate().refresh(t);
    }

    public Serializable save(T t)throws DataAccessException{
    	
        try{ getHibernateTemplate().save(t);
        
        }catch(Exception e){
        	System.out.println(e.getMessage());
        }
        
        return null;//getHibernateTemplate().save(t);
    }

    public void saveOrUpdateAll(Collection<T> entities)
            throws DataAccessException {
        getHibernateTemplate().saveOrUpdateAll(entities);
    }

    public void update(T t, LockMode lockMode) throws DataAccessException {
        getHibernateTemplate().update(t, lockMode);
    }

    public void update(T t) throws DataAccessException {
        getHibernateTemplate().update(t);
    }

    public List<T> list() throws DataAccessException {
        return getHibernateTemplate().loadAll(getEntityClass());

    }

    public List<T> findByNamedQuery(String queryName)
            throws DataAccessException {
        return getHibernateTemplate().findByNamedQuery(queryName);
    }

    public List<T> findByNamedQuery(String queryName, Object value)
            throws DataAccessException {
        return getHibernateTemplate().findByNamedQuery(queryName, value);
    }

    public List<T> findByNamedQuery(String queryName, Object[] values)
            throws DataAccessException {
        return getHibernateTemplate().findByNamedQuery(queryName, values);
    }

    public PaginationSupport findPageByCriteria(
            final DetachedCriteria detachedCriteria, final int pageSize,
            final int startIndex) {
        return (PaginationSupport) getHibernateTemplate().execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session)
                            throws HibernateException {
                        Criteria criteria = detachedCriteria
                                .getExecutableCriteria(session);
                        int totalCount = (Integer) criteria.setProjection(
                                Projections.rowCount()).uniqueResult();
                        criteria.setProjection(null);
                        List items = criteria.setFirstResult(startIndex)
                                .setMaxResults(pageSize).list();
                        return new PaginationSupport(items,
                                totalCount, pageSize, startIndex);
                    }
                });
    }

    public PaginationSupport findPageByQuery(final String hsql,
                                             final int pageSize, final int startIndex) {
        return (PaginationSupport) getHibernateTemplate().execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session)
                            throws HibernateException, SQLException {
                        Query query = session.createQuery(hsql);
                        int totalCount = query.list().size();
                        query.setFirstResult(startIndex);
                        query.setMaxResults(pageSize);
                        List items = query.list();
                        return new PaginationSupport(items,
                                totalCount, pageSize, startIndex);

                    }
                });
    }

	public void merge(T t) throws DataAccessException {
		this.getHibernateTemplate().merge(t);		
	}

}
